#!/usr/bin/perl
# file: facfib.pl
use strict;
my $arg = shift || 10;
pipe (READER,WRITER) or die "Can't open pipe: $!\n";        #建立管道，READER将被父进程用来从子进程读取结果，子进程将使用WRITER来写它们的结果
if (fork == 0){             #创建一个子进程，调用 fork 复制当前进程。如果是子进程，fork返回0
    close READER;           #在子进程中关掉不需要的 READER 文件句柄，
    select WRITER; $| = 1;  #调用select 选择WRITER，使它成为默认文件句柄，通过$|打开autoflush模式，确保父进程当我们一写消息就能立刻收到。
    factorial ($arg);       
    exit 0;                 #当factorial调用结束后终止
}
if(fork != 0){
    close READER;
    select WRITER; $| = 1;
    my $result = fibonacci($arg);
    exit 0;
}

# parent process closes writer and reads from reader
close WRITER;               # 父进程中关闭writer，然后从reader中一次读取一行并打印结果。这些将包含两个子进程产生的行。
print while <READER>;       # 
sub factorial{
    my $target = shift;
    for (my $result = 1, my $i = 1; $i <= $target; $i++){
        print "factorial($i) =>", $result *= $i, "\n";
    }
}

sub fibonacci{
    my $target = shift;
    my ($a, $b) = (1, 0);
    for(my $i = 1; $i <= $target; $i++){
        my $c = $a + $b;
        print "fibonacci ($i) => $c\n";
        ($a, $b) = ($b, $c);
    }
}

=pod
强大的 pipe 管道

pipe 创建一对文件句柄：一个用于读，一个用于写。对一个文件句柄写的任何内容都能从另一个文件句柄读取。

$result = pipe (READHANDLE, WRITEHANDLE);
打开由管道连接的一对文件句柄。第一个参数是要读取的文件句柄的名字，第二个参数是用来写的文件句柄的名字。
如果成功执行，pipe 返回一个 true 结果码。

pipe 通常与 fork 结合使用，用来创建一对能够改变数据的父进程和子进程。
父进程保留一个文件句柄并关闭另外一个文件句柄，子进程和父进程正好相反。
现在父进程和子进程并行工作是可以通过管道来通信。
=cut

